﻿using DimensionsHelper.Common.Contracts;
using DimensionsHelper.Common.Contracts.Services;

namespace DimensionsHelper.Client.ViewModels;

public abstract partial class JsonLoaderViewModelBase : ObservableObject, IProjectService
{
    private const string HistoryFileCategory = "历史文件";
    private const string PresetFileCategory = "预设文件";


    [ObservableProperty]
    private bool _isBusy;


    [ObservableProperty]
    private string _jsonPath = string.Empty;


    [ObservableProperty]
    private FileInfoViewModel? _knownJsonFileInfo;


    protected JsonLoaderViewModelBase(IServiceProvider serviceProvider)
    {
        ServiceProvider = serviceProvider;
        OptionalFileSource = new JsonOptionalFileSource(this);
        InitializeOptionalJson();
        PropertyChanged += OnJsonFileInfoPropertyChanged;
    }

    private bool UpdatingJsonInternal { get; set; }
    
    public IServiceProvider ServiceProvider { get; }

    protected JsonOptionalFileSource OptionalFileSource { get; }

    public abstract string HistoryJsonSettingName { get; }

    public ObservableCollection<FileInfoViewModel> OptionalFiles { get; } = [];

    public abstract string Section { get; }

    public IFilePikerService? FilePikerService
    {
        get; set;
    }

    public IReportService? ReportService
    {
        get; set;
    }


    private void InitializeOptionalJson()
    {
        foreach (string jsonName in OptionalFileSource.OptionalJsonList)
        {
            AddOptionalJsonInternal(jsonName, OptionalFileSource.IsPresetJson(jsonName));
        }
    }


    private void OnJsonFileInfoPropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case nameof(KnownJsonFileInfo) when UpdatingJsonInternal is false && KnownJsonFileInfo is not null:
            {
                UpdatingJsonInternal = true;
                JsonPath = KnownJsonFileInfo.FileName;
                UpdatingJsonInternal = false;
                break;
            }

            case nameof(JsonPath) when UpdatingJsonInternal is false:
            {
                UpdatingJsonInternal = true;
                KnownJsonFileInfo = OptionalFiles.FirstOrDefault(f =>
                    f.FileName.Equals(JsonPath, StringComparison.OrdinalIgnoreCase));
                UpdatingJsonInternal = false;
                break;
            }
        }
    }


    private void AddOptionalJsonInternal(string jsonName, bool isPreset)
    {
        FileInfoViewModel fileInfo = ServiceProvider.GetRequiredService<FileInfoViewModel>();
        fileInfo.FileName = jsonName;

        if (!isPreset)
        {
            fileInfo.RemoveSelf += OnHistoricalJsonRemoveSelf;
            fileInfo.Category = HistoryFileCategory;
        }
        else
        {
            fileInfo.Category = PresetFileCategory;
        }

        OptionalFiles.Add(fileInfo);
    }


    public void AddHistoricalJson(string jsonName)
    {
        if (OptionalFileSource.IsPresetOrHistoryJson(jsonName))
        {
            return;
        }

        AddOptionalJsonInternal(jsonName, false);
    }


    private void OnHistoricalJsonRemoveSelf(FileInfoViewModel fileInfo)
    {
        OptionalFileSource.RemoveHistoryJsonName(fileInfo.FileName);
        OptionalFiles.Remove(fileInfo);
    }


    [RelayCommand]
    private void ClearHistory()
    {
        OptionalFileSource.ClearHistoryJson();
        OptionalFiles.Clear();
        KnownJsonFileInfo = null;
        InitializeOptionalJson();
    }

    public abstract bool LoadJson();

    public abstract Task<bool> SaveJson(bool saveAs);


    protected abstract RunnableContainer? GetRunnableContainer();


    [RelayCommand]
    private void Execute()
    {
        RunnableContainer? container = GetRunnableContainer();

        if (container == null)
        {
            return;
        }

        WeakReferenceMessenger.Default.Send((IRunnable)container);
    }
}